package com.liang.leetcode.user.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liang.leetcode.common.enums.user.UserRole;
import com.liang.leetcode.common.enums.user.UserStatus;
import com.liang.leetcode.common.exception.ClientException;
import com.liang.leetcode.user.config.OAuthProperties;
import com.liang.leetcode.user.domain.entity.OAuthUserInfo;
import com.liang.leetcode.user.domain.entity.User;
import com.liang.leetcode.user.domain.entity.UserOAuth;
import com.liang.leetcode.user.mapper.UserOAuthMapper;
import com.liang.leetcode.user.service.OAuthService;
import com.liang.leetcode.user.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;

/**
 * OAuth第三方登录服务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OAuthServiceImpl extends ServiceImpl<UserOAuthMapper, UserOAuth> implements OAuthService {

    private final UserService userService;
    private final OAuthProperties oauthProperties;
    private final RBloomFilter<String> userOAuthBloomFilter;

    @Override
    public String getAuthorizeUrl(String provider) {
        OAuthProperties.OAuthConfig config = oauthProperties.getConfigByPlatform(provider);
        if (config == null) {
            throw new ClientException("不支持的平台: " + provider);
        }

        // 根据不同平台构建授权URL
        StringBuilder url = new StringBuilder(config.getAuthorizeUrl());
        url.append("?client_id=").append(config.getClientId());
        url.append("&redirect_uri=").append(config.getRedirectUri());

        // 根据平台添加特定参数
        switch (provider.toUpperCase()) {
            case "GITHUB":
                url.append("&scope=user:email");
                break;
            case "QQ":
                url.append("&response_type=code");
                break;
            case "GOOGLE":
                url.append("&response_type=code");
                url.append("&scope=openid%20email%20profile");
                break;
        }

        return url.toString();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String handleCallback(String provider, String code) {
        // 1. 获取第三方用户信息
        OAuthUserInfo oauthUserInfo = fetchOAuthUserInfo(provider, code);

        // 2. 构建布隆过滤器key: provider:providerUserId
        String bloomKey = provider.toLowerCase() + ":" + oauthUserInfo.getProviderUserId();
        log.info("布隆过滤器key: {}", bloomKey);

        Long userId;

        // 3. 使用布隆过滤器快速判断
        if (!userOAuthBloomFilter.contains(bloomKey)) {
            // ===== 场景1: 布隆过滤器判断 "一定不存在" =====
            log.info("布隆过滤器判断: {} 不存在，直接创建新用户", bloomKey);
            userId = createNewUserWithOAuth(provider, oauthUserInfo);

            // 重要：新增后要添加到布隆过滤器
            userOAuthBloomFilter.add(bloomKey);
            log.info("已将 {} 添加到布隆过滤器", bloomKey);
        } else {
            // ===== 场景2: 布隆过滤器判断 "可能存在" =====
            log.info("布隆过滤器判断: {} 可能存在，需要查询数据库确认", bloomKey);

            // 从数据库查询确认
            UserOAuth existingOAuth = lambdaQuery()
                    .eq(UserOAuth::getProvider, provider.toLowerCase())
                    .eq(UserOAuth::getProviderUserId, oauthUserInfo.getProviderUserId())
                    .eq(UserOAuth::getDeleted, 0)
                    .one();
            if (existingOAuth != null) {
                // 真的存在，说明是老用户
                log.info("数据库确认: {} 存在，用户ID={}", bloomKey, existingOAuth.getUserId());
                // 更新token等信息
                existingOAuth.setAccessToken(oauthUserInfo.getAccessToken());
                lambdaUpdate()
                        .set(UserOAuth::getAccessToken, oauthUserInfo.getAccessToken())
                        .eq(UserOAuth::getId, existingOAuth.getId())
                        .update();
                userId = existingOAuth.getUserId();
            } else {
                // 不存在，说明是布隆过滤器误判（小概率事件）
                log.warn("数据库确认: {} 不存在，布隆过滤器误判！创建新用户", bloomKey);
                userId = createNewUserWithOAuth(provider, oauthUserInfo);
            }
        }

        // 4. 生成登录token（使用Sa-Token）
        StpUtil.login(userId);
        return StpUtil.getTokenValue();
    }

    /**
     * 创建新用户并绑定第三方账号
     */
    private Long createNewUserWithOAuth(String provider, OAuthUserInfo oauthUserInfo) {
        // 创建user
        User newUser = User.builder()
                .username(oauthUserInfo.getProviderUsername())
                .email(oauthUserInfo.getEmail())
                .nickname(oauthUserInfo.getProviderUsername())
                .avatar(oauthUserInfo.getAvatarUrl())
                .status(UserStatus.NORMAL.getCode())
                .role(UserRole.NORMAL.getCode())
                .solvedCount(0)
                .submitCount(0)
                .build();
        userService.save(newUser);
        log.info("创建新用户成功: userId={}, username={}", newUser.getId(), newUser.getUsername());

        // 创建user_oauth绑定关系
        UserOAuth userOAuth = UserOAuth.builder()
                .userId(newUser.getId())
                .provider(provider.toLowerCase())
                .providerUserId(oauthUserInfo.getProviderUserId())
                .providerUsername(oauthUserInfo.getProviderUsername())
                .accessToken(oauthUserInfo.getAccessToken())
                .avatarUrl(oauthUserInfo.getAvatarUrl())
                .email(oauthUserInfo.getEmail())
                .build();
        baseMapper.insert(userOAuth);
        log.info("创建OAuth绑定成功: provider={}, providerUserId={}", provider, oauthUserInfo.getProviderUserId());

        return newUser.getId();
    }

    /**
     * 获取第三方平台用户信息
     */
    private OAuthUserInfo fetchOAuthUserInfo(String provider, String code) {
        // 目前只实现了GitHub，后续可以扩展其他平台
        if (!"github".equalsIgnoreCase(provider)) {
            throw new ClientException("暂不支持该平台: " + provider);
        }

        // 1. 获取access_token
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("client_id", "Ov23liVIpvqDfmNGrjzj");
        paramMap.put("client_secret", "53da6365a9e5c1b7c5bbdc701a262d3ed688b1cc");
        paramMap.put("code", code);
        paramMap.put("accept", "json");
        String result = HttpUtil.post("https://github.com/login/oauth/access_token", paramMap);
        log.info("获取token结果: {}", result);

        // 2. 解析token
        String token = result.split("&")[0].split("=")[1];

        // 3. 获取第三方平台用户信息
        String userInfoJson = HttpRequest.get("https://api.github.com/user")
                .header("Authorization", "token " + token)
                .header("X-GitHub-Api-Version", "2022-11-28")
                .execute().body();

        JSONObject githubUser = JSON.parseObject(userInfoJson);

        OAuthUserInfo userInfo = new OAuthUserInfo();
        userInfo.setProviderUserId(githubUser.getString("id"));
        userInfo.setProviderUsername(githubUser.getString("login"));
        userInfo.setEmail(githubUser.getString("email"));
        userInfo.setAvatarUrl(githubUser.getString("avatar_url"));
        userInfo.setAccessToken(token);

        log.info("获取到{}用户信息: id={}, login={}, email={}",
                provider, userInfo.getProviderUserId(), userInfo.getProviderUsername(), userInfo.getEmail());
        return userInfo;
    }
}